package com.duniptech.engine.core.modeling;

import java.util.HashSet;
import java.util.Set;

import com.duniptech.engine.core.modeling.api.IAtomic;
import com.duniptech.engine.core.modeling.api.ICoupled;
import com.duniptech.engine.core.modeling.api.IMessage;
import com.duniptech.engine.core.modeling.api.IVariableStructure;
import com.duniptech.engine.core.simulation.api.ISimulator;

import org.w3c.dom.Element;


/**
 * Abstract class defining  atomic models. 
 * 
 * @author Jos� Luis Risco.
 */

public abstract class Atomic implements IAtomic, IVariableStructure {
	
	private static final long serialVersionUID = 2L;
	
	// Father of the current model
	private ICoupled parent;
	private String name;
	private String phase;
	private double sigma;
	private Set<String> inPortNames;
	private Set<String> outPortNames;
	
	private ISimulator simulator;
	
		
	/** 
	 * Constructor.
	 * @param name Name of this component. 
	 */
	public Atomic(String name) {
		parent = null;
		this.name = name;
		phase = "passive";
		sigma = INFINITY;
		inPortNames = new HashSet<String>();
		outPortNames = new HashSet<String>();
	}

	/**
	 * Constructor.
	 * @param xmlNode in the form:
	 * <atomic name="name" phase="passive" sigma="INFINITY" class="lib.atomic...">
	 *  ...
	 * </atomic>
	 */
	public Atomic(Element xmlNode) {
		this(xmlNode.getAttribute("name"));
		setPhase(xmlNode.getAttribute("phase"));
		String sigmaAsString = xmlNode.getAttribute("sigma");
		if(sigmaAsString.equals("INFINITY"))
			setSigma(INFINITY);
		else
			setSigma(Double.valueOf(sigmaAsString));
	}
	// ---------------------------------------------------------------
	// DEVS PROTOCOL
	// ---------------------------------------------------------------
	public double ta() { return getSigma(); }
	abstract public void deltint();
	abstract public void deltext(double e, IMessage x);
	public void deltcon(double e, IMessage x) {
		deltint();
		deltext(0,x);
	}
	abstract public IMessage lambda();
	public ICoupled getParent() { return parent; }
	public void setParent(ICoupled parent) { this.parent = parent; }
	public String getPhase() { return phase; }
	public String getName() { return name; }
	public void setName(String name) { this.name = name; }
	public void setPhase(String phase) { this.phase = phase; }
	public double getSigma() { return sigma; }
	public void setSigma(double sigma) { this.sigma = sigma; }
	
	// EXTRA FUNCTIONALLITY
	// EXTRA FUNTIONALLITY
	public void passivate() {
		this.phase = "passive";
		this.sigma = INFINITY;
	}
	public void holdIn(String phase, double sigma) {
		this.phase = phase;
		this.sigma = sigma;
	}
	
	public void advance(double e) {
		sigma = sigma - e;
	}

	public void addInport(String name) {
		if(!containsInPort(name))
			inPortNames.add(name);
	}
	
	public void removeInport(String name){
		if(containsInPort(name))
			inPortNames.remove(name);
	}
	
	public void addOutport(String name) {
		if(!containsOutPort(name))
			outPortNames.add(name);
	}
	
	public void removeOutport(String name){
		if(containsOutPort(name))
			outPortNames.remove(name);
	}
	
	public Set<String> getInportNames() { return inPortNames; }
	
	public Set<String> getOutportNames() { return outPortNames; }
	
	public boolean containsInPort(String portName) {
		return inPortNames.contains(portName.trim());
	}
	
	public boolean containsOutPort(String portName) {
		return outPortNames.contains(portName.trim());
	}
	
	public void setSimulator(ISimulator simulator) {
		this.simulator = simulator;	
	}
	
	public ISimulator getSimulator() {
		return simulator;
	}
	
	public void logState(){
		StringBuffer sb = new StringBuffer();
		sb.append("Model: "+getName()+"\t[");
		sb.append("Phase:"+getPhase()+" ");
		sb.append("Sigma:"+getSigma()+" ]");
		System.out.println(sb.toString());
	}
	
	//IVariableStructure
	public void addModel(IAtomic model){
		
	}
	
	public void removeModel(IAtomic model){
		
	}
}
